import Blockly from 'blockly/core'
import 'blockly/python_compressed'
import 'blockly/blockly_compressed'
import 'blockly/blocks_compressed'

Blockly.Blocks.function_lambda = {
  init: function () {
    this.appendValueInput('LAMBDASTATE').appendField('lambda')
    this.setHelpUrl()
    this.setColour(230)
    this.itemCount_ = 3
    this.updateShape_()
    this.setOutput(true, null)
    this.setMutator(new Blockly.Mutator(['lambda_create_with_item']))
    this.setTooltip()
  },
  updateShape_: function () {
    if (this.itemCount_ && this.getInput('EMPTY')) {
      this.removeInput('EMPTY')
    } else if (!this.itemCount_ && !this.getInput('EMPTY')) {
      this.appendDummyInput('EMPTY').appendField('lambda')
    }
    // Add new inputs.
    for (let i = 0; i < this.itemCount_; i++) {
      if (!this.getInput('ADD' + i)) {
        const input = this.appendValueInput('ADD' + i).setAlign(
          Blockly.ALIGN_RIGHT
        )
        if (i === 0) {
          input.appendField('argument')
        }
      }
    }
    let replacement = this.itemCount_
    while (this.getInput('ADD' + replacement)) {
      this.removeInput('ADD' + replacement)
      replacement++
    }
  },

  mutationToDom: function () {
    const container = Blockly.utils.xml.createElement('mutation')
    container.setAttribute('items', this.itemCount_)
    return container
  },

  domToMutation: function (xmlElement) {
    this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10)
    this.updateShape_()
  },

  compose: function (containerBlock) {
    let itemBlock = containerBlock.getInputTargetBlock('STACK')
    const connections = []
    while (itemBlock && !itemBlock.isInsertionMarker()) {
      connections.push(itemBlock.valueConnection_)
      itemBlock =
        itemBlock.nextConnection && itemBlock.nextConnection.targetBlock()
    }
    let i = 0
    while (i < this.itemCount_) {
      const connection = this.getInput('ADD' + i).connection.targetConnection
      if (connection && connections.indexOf(connection) === -1) {
        connection.disconnect()
      }
      i++
    }
    this.itemCount_ = connections.length
    this.updateShape_()
    let j = 0
    while (j < this.itemCount_) {
      Blockly.Mutator.reconnect(connections[j], this, 'ADD' + j)
      j++
    }
  },
  decompose: function (workspace) {
    const containerBlock = workspace.newBlock('lambda_create_with_container')
    containerBlock.initSvg()
    let connection = containerBlock.getInput('STACK').connection
    for (let i = 0; i < this.itemCount_; i++) {
      const itemBlock = workspace.newBlock('lambda_create_with_item')
      itemBlock.initSvg()
      connection.connect(itemBlock.previousConnection)
      connection = itemBlock.nextConnection
    }
    return containerBlock
  },

  saveConnections: function (containerBlock) {
    let itemBlock = containerBlock.getInputTargetBlock('STACK')
    let i = 0
    while (itemBlock) {
      const input = this.getInput('ADD' + i)
      itemBlock.valueConnection_ = input && input.connection.targetConnection
      i++
      itemBlock =
        itemBlock.nextConnection && itemBlock.nextConnection.targetBlock()
    }
  }
}

Blockly.Blocks.lambda_create_with_container = {
  init: function () {
    this.setStyle('list_blocks')
    this.appendDummyInput().appendField('add argument')
    this.appendStatementInput('STACK')
    this.setTooltip('add argument')
    this.contextMenu = false
  }
}

Blockly.Blocks.lambda_create_with_item = {
  init: function () {
    this.setStyle('list_blocks')
    this.appendDummyInput().appendField('argument')
    this.setPreviousStatement(true)
    this.setNextStatement(true)
    this.setTooltip('lambda')
    this.contextMenu = false
    this.setColour(230)
  }
}

Blockly.Python.function_lambda = function (block) {
  const statement = Blockly.Python.valueToCode(
    block,
    'LAMBDASTATE',
    Blockly.Python.ORDER_NONE
  )
  const elements = new Array(block.itemCount_)
  for (let i = 0; i < block.itemCount_; i++) {
    elements[i] =
      Blockly.Python.valueToCode(block, 'ADD' + i, Blockly.Python.ORDER_NONE) ||
      'None'
  }
  const code = 'lambda ' + elements.join(', ') + ' : ' + statement + '\n'
  return [code, Blockly.Python.ORDER_NONE]
}

export default Blockly
